package com.ruoyi.framework.shiro.util.secret;

import javax.crypto.Cipher;
import java.io.ByteArrayOutputStream;
import java.nio.charset.StandardCharsets;
import java.security.*;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;

@SuppressWarnings({ "restriction", "unused" })
public class RsaUtils {
	 public static final String KEY_ALGORITHM = "RSA";
	    public static final String PUBLIC_KEY = "RSAPublicKey";
	    public static final String PRIVATE_KEY = "RSAPrivateKey";
	    public static final String SIGNATURE_ALGORITHM="MD5withRSA";
	     /**
	     * RSA最大加密明文大小
	     */
	    private static final int MAX_ENCRYPT_BLOCK = 117;

	    /**
	     * RSA最大解密密文大小
	     */
	    private static final int MAX_DECRYPT_BLOCK = 128;
	    //获得公钥字符串
	    public static String getPublicKeyStr(Map<String, Object> keyMap) throws Exception {
	        //获得map中的公钥对象 转为key对象
	        Key key = (Key) keyMap.get(PUBLIC_KEY);
	        //编码返回字符串
	        return encryptBASE64(key.getEncoded());
	    }


	    //获得私钥字符串
	    public static String getPrivateKeyStr(Map<String, Object> keyMap) throws Exception {
	        //获得map中的私钥对象 转为key对象
	        Key key = (Key) keyMap.get(PRIVATE_KEY);
	        //编码返回字符串
	        return encryptBASE64(key.getEncoded());
	    }

	    //获取公钥
	    public static PublicKey getPublicKey(String key) throws Exception {
	        byte[] keyBytes;
	        keyBytes = Base64.getDecoder().decode(key);
	        X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes);
	        KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
	        PublicKey publicKey = keyFactory.generatePublic(keySpec);
	        return publicKey;
	    }

	    //获取私钥
	    public static PrivateKey getPrivateKey(String key) throws Exception {
	        byte[] keyBytes;
	        keyBytes = Base64.getDecoder().decode(key);
	        PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(keyBytes);
	        KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
	        PrivateKey privateKey = keyFactory.generatePrivate(keySpec);
	        return privateKey;
	    }

	    //解码返回byte
	    public static byte[] decryptBASE64(String key) throws Exception {
	        return Base64.getDecoder().decode(key);
	    }


	    //编码返回字符串
	    public static String encryptBASE64(byte[] key) throws Exception {
	        return Base64.getEncoder().encodeToString(key);
	    }

	    //***************************签名和验证*******************************
	    public static byte[] sign(byte[] data,String privateKeyStr) throws Exception{
	      PrivateKey priK = getPrivateKey(privateKeyStr);
	      Signature sig = Signature.getInstance(SIGNATURE_ALGORITHM);
	      sig.initSign(priK);
	      sig.update(data);
	      return sig.sign();
	    }

	    public static boolean verify(byte[] data,byte[] sign,String publicKeyStr) throws Exception{
	      PublicKey pubK = getPublicKey(publicKeyStr);
	      Signature sig = Signature.getInstance(SIGNATURE_ALGORITHM);
	      sig.initVerify(pubK);
	      sig.update(data);
	      return sig.verify(sign);
	    }

	  //************************加密解密**************************
	    public static byte[] encrypt(byte[] plainText,String publicKeyStr)throws Exception{
	        PublicKey publicKey = getPublicKey(publicKeyStr);
	        Cipher cipher = Cipher.getInstance(KEY_ALGORITHM);//NOSONAR  sonar扫描忽略这段代码
	        cipher.init(Cipher.ENCRYPT_MODE, publicKey);
	        int inputLen = plainText.length;
	        ByteArrayOutputStream out = new ByteArrayOutputStream();
	        int offSet = 0;
	        int i = 0;
	        byte[] cache;
	        while (inputLen - offSet > 0) {
	            if (inputLen - offSet > MAX_ENCRYPT_BLOCK) {
	                cache = cipher.doFinal(plainText, offSet, MAX_ENCRYPT_BLOCK);
	            } else {
	                cache = cipher.doFinal(plainText, offSet, inputLen - offSet);
	            }
	            out.write(cache, 0, cache.length);
	            i++;
	            offSet = i * MAX_ENCRYPT_BLOCK;
	        }
	        byte[] encryptText = out.toByteArray();
	        out.close();
	        return encryptText;
	    }

	    public static byte[] decrypt(byte[] encryptText,String privateKeyStr)throws Exception{
	        PrivateKey privateKey = getPrivateKey(privateKeyStr);
	        Cipher cipher = Cipher.getInstance(KEY_ALGORITHM);//NOSONAR  sonar扫描忽略这段代码
	        cipher.init(Cipher.DECRYPT_MODE, privateKey);
	        int inputLen = encryptText.length;
	        ByteArrayOutputStream out = new ByteArrayOutputStream();
	        int offSet = 0;
	        byte[] cache;
	        int i = 0;
	        // 对数据分段解密
	        while (inputLen - offSet > 0) {
	            if (inputLen - offSet > MAX_DECRYPT_BLOCK) {
	                cache = cipher.doFinal(encryptText, offSet, MAX_DECRYPT_BLOCK);
	            } else {
	                cache = cipher.doFinal(encryptText, offSet, inputLen - offSet);
	            }
	            out.write(cache, 0, cache.length);
	            i++;
	            offSet = i * MAX_DECRYPT_BLOCK;
	        }
	        byte[] plainText = out.toByteArray();
	        out.close();
	        return plainText;
	    }

	    /**
	     * RSA公钥加密
	     *
	     * @param str
	     *            加密字符串
	     * @param publicKey
	     *            公钥
	     * @return 密文
	     * @throws Exception
	     *             加密过程中的异常信息
	     */
	    public static String encryptStr( String str, String publicKey ) throws Exception{
	        //base64编码的公钥
	        byte[] decoded = Base64.getDecoder().decode(publicKey);
	        RSAPublicKey pubKey = (RSAPublicKey) KeyFactory.getInstance("RSA").generatePublic(new X509EncodedKeySpec(decoded));
	        //RSA加密
	        Cipher cipher = Cipher.getInstance("RSA");//NOSONAR  sonar扫描忽略这段代码
	        cipher.init(Cipher.ENCRYPT_MODE, pubKey);
	        String outStr = Base64.getEncoder().encodeToString(cipher.doFinal(str.getBytes(StandardCharsets.UTF_8)));
	        return outStr;
	    }

	    /**
	     * RSA私钥解密
	     *
	     * @param str
	     *            加密字符串
	     * @param privateKey
	     *            私钥
	     * @return 铭文
	     * @throws Exception
	     *             解密过程中的异常信息
	     */
	    public static String decryptStr(String str, String privateKey) throws Exception{
	        //64位解码加密后的字符串
	        byte[] inputByte = Base64.getDecoder().decode(str);
	        //base64编码的私钥
	        byte[] decoded = Base64.getDecoder().decode(privateKey);
	        RSAPrivateKey priKey = (RSAPrivateKey) KeyFactory.getInstance("RSA").generatePrivate(new PKCS8EncodedKeySpec(decoded));
	        //RSA解密
	        Cipher cipher = Cipher.getInstance("RSA");//NOSONAR  sonar扫描忽略这段代码
	        cipher.init(Cipher.DECRYPT_MODE, priKey);
	        String outStr = new String(cipher.doFinal(inputByte));
	        return outStr;
	    }

	    public static Map<String, Object> initKey() throws Exception {
			KeyPairGenerator keyPairGen = KeyPairGenerator
					.getInstance(KEY_ALGORITHM);
			keyPairGen.initialize(1024);//NOSONAR  sonar扫描忽略这段代码
			KeyPair keyPair = keyPairGen.generateKeyPair();
			RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
			RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();
			Map<String, Object> keyMap = new HashMap<String, Object>(2);
			keyMap.put(PUBLIC_KEY, publicKey);
			keyMap.put(PRIVATE_KEY, privateKey);
			return keyMap;
		}

}
